/*  
 *   *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.  
 *    *  
 *     *  Licensed under the Apache License, Version 2.0 (the License); you may  
 *      *  not use this file except in compliance with the License.  
 *       *  
 *        *  http://www.apache.org/licenses/LICENSE-2.0  
 *         */  

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <stdint.h>  
#include "gmssl/sm4.h"
#include "gmssl/rand.h"

#define PLAINTEXT_MIN_SIZE 130  

int main() {  
	    
	    uint8_t key[SM4_KEY_SIZE];  
	        if (rand_bytes(key, SM4_KEY_SIZE) != 1) {  
			        fprintf(stderr, "随机密钥生成失败。\n");  
				        return EXIT_FAILURE;  
					    }  

		    uint8_t iv[SM4_BLOCK_SIZE];  
		        if (rand_bytes(iv, SM4_BLOCK_SIZE) != 1) {  
				        fprintf(stderr, "随机IV生成失败。\n");  
					        return EXIT_FAILURE;  
						    }  
			 
			    printf("随机生成的密钥: ");  
			        for (size_t i = 0; i < SM4_KEY_SIZE; i++) {  
					        printf("%02X ", key[i]);  
						    }  
				    printf("\n");  

				        printf("随机生成的IV: ");  
					    for (size_t i = 0; i < SM4_BLOCK_SIZE; i++) {  
						            printf("%02X ", iv[i]);  
							        }  
					        printf("\n");  
						 
						    uint8_t plaintext[PLAINTEXT_MIN_SIZE];  
						        if (rand_bytes(plaintext, PLAINTEXT_MIN_SIZE) != 1) {  
								        fprintf(stderr, "随机明文生成失败。\n");  
									        return EXIT_FAILURE;  
										    }  
							 
							    printf("明文 (%d 字节): ", PLAINTEXT_MIN_SIZE);  
							        for (size_t i = 0; i < PLAINTEXT_MIN_SIZE; i++) {  
									        printf("%02X ", plaintext[i]);  
										    }  
								    printf("\n");  

								        SM4_KEY enc_key, dec_key;  
									    sm4_set_encrypt_key(&enc_key, key);  
									        sm4_set_decrypt_key(&dec_key, key);  

										    size_t plaintext_len = PLAINTEXT_MIN_SIZE;  
										        size_t max_ciphertext_len = plaintext_len + SM4_BLOCK_SIZE;  
											    uint8_t *ciphertext = malloc(max_ciphertext_len);  
											        if (ciphertext == NULL) {  
													        fprintf(stderr, "内存分配失败。\n");  
														        return EXIT_FAILURE;  
															    }  

												    uint8_t *decryptedtext = malloc(max_ciphertext_len + 1); // +1用于终止符  
												        if (decryptedtext == NULL) {  
														        fprintf(stderr, "内存分配失败。\n");  
															        free(ciphertext);  
																        return EXIT_FAILURE;  
																	    }  

													    size_t outlen;  
													        int ret;  

														    ret = sm4_cbc_padding_encrypt(&enc_key, iv, plaintext, plaintext_len, ciphertext, &outlen);  
														        if (ret != 1) {  
																        fprintf(stderr, "加密失败。\n");  
																	        free(ciphertext);  
																		        free(decryptedtext);  
																			        return EXIT_FAILURE;  
																				    }  

															    printf("密文 (%zu 字节): ", outlen);  
															        for (size_t i = 0; i < outlen; i++) {  
																	        printf("%02X ", ciphertext[i]);  
																		    }  
																    printf("\n");  

																        ret = sm4_cbc_padding_decrypt(&dec_key, iv, ciphertext, outlen, decryptedtext, &outlen);  
																	    if (ret != 1) {  
																		            fprintf(stderr, "解密失败。\n");  
																			            free(ciphertext);  
																				            free(decryptedtext);  
																					            return EXIT_FAILURE;  
																						        }  

																	        decryptedtext[outlen] = '\0';  

																		    printf("解密后的明文 (%zu 字节): ", outlen);  
																		        for (size_t i = 0; i < outlen; i++) {  
																				        printf("%02X ", decryptedtext[i]);  
																					    }  
																			    printf("\n");  

																			        if (memcmp(plaintext, decryptedtext, plaintext_len) == 0) {  
																					        printf("解密验证成功：解密后的明文与原始明文一致。\n");  
																						    } else {  
																							            printf("解密验证失败：解密后的明文与原始明文不一致。\n");  
																								        }  

																				    free(ciphertext);  
																				        free(decryptedtext);  

																					    return EXIT_SUCCESS;  
}
